<template>
  <div class="container d-flex flex-col gap-col-8">
    <div v-if="isReady" class="font-size-12 font-weight-400 line-height-875">{{ $t('payment.creditCard.title') }}</div>
    <form id="payment-form" @submit.prevent="onSubmit">
      <div class="d-flex flex-col gap-col-8">
        <div class="d-flex flex-col gap-col-8">
          <div class="payment-container" id="payment-element"></div>
          <CheckBox
            v-if="isReady"
            v-model="checkbox.value"
            :info="$t('payment.creditCard.agreeInfo')"
            :error="checkbox.error"
          ></CheckBox>
          <div v-if="stripeError" class="text-primary-x font-size-12 font-weight-500 line-height-123">
            {{ stripeError }}
          </div>
        </div>
      </div>
      <button id="payment-submit-btn" type="submit" style="visibility: hidden"></button>
    </form>
    <div v-if="isReady" class="d-flex flex-col gap-col-8">
      <div class="d-flex flex-row gap-row-8">
        <img v-for="img in imgs" :key="`payment-${img.alt}`" :src="img.src" :alt="img.alt" />
      </div>
      <div class="font-size-10 font-weight-400 line-height-120 text-gray-x2">
        {{ $t('payment.creditCard.footer') }}
      </div>
    </div>
    <div v-if="!isReady" class="d-flex flex-col gap-col-8 loading">
      <div class="card-region"></div>
      <div class="check"></div>
      <div class="cards"></div>
    </div>
  </div>
</template>
<script setup>
import { loadStripe } from '@stripe/stripe-js'
import { onDeactivated, onMounted, reactive, ref } from 'vue'
import { $t } from '@/i18n'
import { useYup, validate } from '@/plugins/yup'
import CheckBox from '@/components/form/CheckBox.vue'
import { themeFantasi } from '@/compositions/payment/stripe/appearance'
import API from '@/http'

const emits = defineEmits(['complete'])

const imgs = [
  { src: '/images/payment/visa.png', alt: 'Visa' },
  { src: '/images/payment/master-card.png', alt: 'Mastercard' },
  { src: '/images/payment/maestro.png', alt: 'Maestro' },
  { src: '/images/payment/diners-club.png', alt: 'DinersClub' },
  { src: '/images/payment/discover.png', alt: 'Discover' },
  { src: '/images/payment/jcb.png', alt: 'JCB' },
]

let stripe
let elements
let clientSecret

const isReady = ref(false)

async function createStripePayment() {
  const { client_secret, publishable_key } = await API.Payment.getStripeKey()
  stripe = await loadStripe(publishable_key)

  elements = stripe.elements({
    clientSecret: client_secret,
    appearance: themeFantasi,
  })

  const paymentElement = elements.create('payment')
  paymentElement.mount('#payment-element')
  paymentElement.on('ready', () => {
    console.log('paymentElement ready')
    isReady.value = true
  })
}

const yup = useYup()
const checkSchema = yup.boolean().required().oneOf([true], { key: 'yup.boolean.oneOf' })

const checkbox = reactive({
  value: false,
  error: '',
  check: false,
})

const stripeError = ref('')

async function onSubmit(e) {
  e.preventDefault()
  try {
    await validate(checkSchema, checkbox)

    if (!checkbox.check) {
      emits('complete', { status: false, intent: null, error: null })
      return
    }

    const setupResponse = await stripe.confirmSetup({
      elements,
      clientSecret,
      redirect: 'if_required',
      confirmParams: {
        return_url: import.meta.env.VITE_APP_URL,
      },
    })

    if (setupResponse.error) {
      stripeError.value = setupResponse.error.message
      emits('complete', { status: false, intent: null, error: setupResponse.error })
      throw new Error(setupResponse.error.message)
    }
    console.log('setupResponse', setupResponse)

    if (setupResponse.setupIntent.status === 'succeeded') {
      emits('complete', { status: true, intent: setupResponse.setupIntent, error: null })
    } else {
      new Promise((resolve, reject) => {
        const retry = 10
        let count = 0

        const interval = setInterval(async () => {
          const { setupIntent } = await stripe.retrieveSetupIntent(setupResponse.setupIntent.client_secret)
          if (setupIntent.status === 'succeeded') {
            clearInterval(interval)
            resolve(setupIntent)
          } else {
            if (count > retry) {
              clearInterval(interval)
              reject(new Error(`setupIntent not succeeded after ${retry} retries`))
            }
            count++
          }
        }, 500)
      })
        .then((setupIntent) => emits('complete', { status: true, intent: setupIntent, error: null }))
        .catch((e) => emits('complete', { status: false, intent: null, error: { message: e } }))
    }
  } catch (e) {
    console.error(`setupIntent.error: ${e}`)
  }
}

const reset = () => {
  stripeError.value = ''
  checkbox.value = false
  checkbox.error = ''
}

onMounted(async () => await createStripePayment())
onDeactivated(reset)
</script>
<style scoped lang="scss">
.container {
  width: 100%;
  height: 100%;
}

@import '@/assets/styles/loading-skeleton.scss';
.loading {
  .card-region,
  .check,
  .cards {
    @include loading-skeleton;
    width: 100%;
    border-radius: 0.25rem;
  }

  .card-region,
  .check,
  .cards {
    height: 1.5rem;
  }
}
</style>
